/**
  ******************************************************************************
  * @file    bl602_uart.c
  * @version V1.0
  * @date
  * @brief   This file is the standard driver c file
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2020 Bouffalo Lab</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of Bouffalo Lab nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

#include "bl602_uart.h"
#include "bl602_glb.h"

/** @addtogroup  BL602_Peripheral_Driver
 *  @{
 */

/** @addtogroup  UART
 *  @{
 */

/** @defgroup  UART_Private_Macros
 *  @{
 */
#define UART_TX_TIMEOUT_COUNT          (160*1000)

/*@} end of group UART_Private_Macros */

/** @defgroup  UART_Private_Types
 *  @{
 */

/*@} end of group UART_Private_Types */

/** @defgroup  UART_Private_Variables
 *  @{
 */
static const uint32_t uartAddr[2] = {UART0_BASE,UART1_BASE};
static intCallback_Type * uartIntCbfArra[2][UART_INT_ALL]= {
    {NULL},{NULL}
};


/*@} end of group UART_Private_Variables */

/** @defgroup  UART_Global_Variables
 *  @{
 */

/*@} end of group UART_Global_Variables */

/** @defgroup  UART_Private_Fun_Declaration
 *  @{
 */
#if (!defined BL602_USE_HAL_DRIVER)||(defined BL602_EFLASH_LOADER)
static void UART_IntHandler(UART_ID_Type uartId);
#endif

/*@} end of group UART_Private_Fun_Declaration */

/** @defgroup  UART_Private_Functions
 *  @{
 */

/****************************************************************************//**
 * @brief  UART interrupt common handler function
 *
 * @param  uartId: UART ID type
 *
 * @return None
 *
*******************************************************************************/
#if (!defined BL602_USE_HAL_DRIVER)||(defined BL602_EFLASH_LOADER)
static void UART_IntHandler(UART_ID_Type uartId)
{
    uint32_t tmpVal = 0;
    uint32_t maskVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    tmpVal = BL_RD_REG(UARTx,UART_INT_STS);
    maskVal = BL_RD_REG(UARTx,UART_INT_MASK);

    /* Length of uart tx data transfer arrived interrupt */
    if(BL_IS_REG_BIT_SET(tmpVal,UART_UTX_END_INT) && !BL_IS_REG_BIT_SET(maskVal,UART_CR_UTX_END_MASK)){
        BL_WR_REG(UARTx,UART_INT_CLEAR,0x1);
        if(uartIntCbfArra[uartId][UART_INT_TX_END] != NULL){
            uartIntCbfArra[uartId][UART_INT_TX_END]();
        }
    }

    /* Length of uart rx data transfer arrived interrupt */
    if(BL_IS_REG_BIT_SET(tmpVal,UART_URX_END_INT) && !BL_IS_REG_BIT_SET(maskVal,UART_CR_URX_END_MASK)){
        BL_WR_REG(UARTx,UART_INT_CLEAR,0x2);
        if(uartIntCbfArra[uartId][UART_INT_RX_END] != NULL){
            uartIntCbfArra[uartId][UART_INT_RX_END]();
        }
    }

    /* Tx fifo ready interrupt,auto-cleared when data is pushed */
    if(BL_IS_REG_BIT_SET(tmpVal,UART_UTX_FIFO_INT) && !BL_IS_REG_BIT_SET(maskVal,UART_CR_UTX_FIFO_MASK)){
        if(uartIntCbfArra[uartId][UART_INT_TX_FIFO_REQ] != NULL){
            uartIntCbfArra[uartId][UART_INT_TX_FIFO_REQ]();
        }
    }

    /* Rx fifo ready interrupt,auto-cleared when data is popped */
    if(BL_IS_REG_BIT_SET(tmpVal,UART_URX_FIFO_INT) && !BL_IS_REG_BIT_SET(maskVal,UART_CR_URX_FIFO_MASK)){
        if(uartIntCbfArra[uartId][UART_INT_RX_FIFO_REQ] != NULL){
            uartIntCbfArra[uartId][UART_INT_RX_FIFO_REQ]();
        }
    }

    /* Rx time-out interrupt */
    if(BL_IS_REG_BIT_SET(tmpVal,UART_URX_RTO_INT) && !BL_IS_REG_BIT_SET(maskVal,UART_CR_URX_RTO_MASK)){
        BL_WR_REG(UARTx,UART_INT_CLEAR,0x10);
        if(uartIntCbfArra[uartId][UART_INT_RTO] != NULL){
            uartIntCbfArra[uartId][UART_INT_RTO]();
        }
    }

    /* Rx parity check error interrupt */
    if(BL_IS_REG_BIT_SET(tmpVal,UART_URX_PCE_INT) && !BL_IS_REG_BIT_SET(maskVal,UART_CR_URX_PCE_MASK)){
        BL_WR_REG(UARTx,UART_INT_CLEAR,0x20);
        if(uartIntCbfArra[uartId][UART_INT_PCE] != NULL){
            uartIntCbfArra[uartId][UART_INT_PCE]();
        }
    }

    /* Tx fifo overflow/underflow error interrupt */
    if(BL_IS_REG_BIT_SET(tmpVal,UART_UTX_FER_INT) && !BL_IS_REG_BIT_SET(maskVal,UART_CR_UTX_FER_MASK)){
        if(uartIntCbfArra[uartId][UART_INT_TX_FER] != NULL){
            uartIntCbfArra[uartId][UART_INT_TX_FER]();
        }
    }

    /* Rx fifo overflow/underflow error interrupt */
    if(BL_IS_REG_BIT_SET(tmpVal,UART_URX_FER_INT) && !BL_IS_REG_BIT_SET(maskVal,UART_CR_URX_FER_MASK)){
        if(uartIntCbfArra[uartId][UART_INT_RX_FER] != NULL){
            uartIntCbfArra[uartId][UART_INT_RX_FER]();
        }
    }
}
#endif


/*@} end of group UART_Private_Functions */

/** @defgroup  UART_Public_Functions
 *  @{
 */

/****************************************************************************//**
 * @brief  UART initialization function
 *
 * @param  uartId: UART ID type
 * @param  uartCfg: UART configuration structure pointer
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_Init(UART_ID_Type uartId,UART_CFG_Type* uartCfg)
{
    uint32_t tmpValTxCfg = 0;
    uint32_t tmpValRxCfg = 0;
    uint32_t fraction = 0;
    uint32_t baudRateDivisor = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_PARITY_TYPE(uartCfg->parity));
    CHECK_PARAM(IS_UART_DATABITS_TYPE(uartCfg->dataBits));
    CHECK_PARAM(IS_UART_STOPBITS_TYPE(uartCfg->stopBits));
    CHECK_PARAM(IS_UART_BYTEBITINVERSE_TYPE(uartCfg->byteBitInverse));

    /* Cal the baud rate divisor */
    fraction = uartCfg->uartClk * 10 / uartCfg->baudRate % 10;
    baudRateDivisor = uartCfg->uartClk / uartCfg->baudRate;
    if(fraction >= 5){
        ++baudRateDivisor;
    }

    /* Set the baud rate register value */
    BL_WR_REG(UARTx,UART_BIT_PRD,((baudRateDivisor-1)<<0x10)|((baudRateDivisor-1)&0xFFFF));

    /* Configure parity type */
    tmpValTxCfg = BL_RD_REG(UARTx,UART_UTX_CONFIG);
    tmpValRxCfg = BL_RD_REG(UARTx,UART_URX_CONFIG);
    switch(uartCfg->parity)
    {
        case UART_PARITY_NONE:
            tmpValTxCfg = BL_CLR_REG_BIT(tmpValTxCfg,UART_CR_UTX_PRT_EN);
            tmpValRxCfg = BL_CLR_REG_BIT(tmpValRxCfg,UART_CR_URX_PRT_EN);
            break;
        case UART_PARITY_ODD:
            tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg,UART_CR_UTX_PRT_EN);
            tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg,UART_CR_UTX_PRT_SEL);
            tmpValRxCfg = BL_SET_REG_BIT(tmpValRxCfg,UART_CR_URX_PRT_EN);
            tmpValRxCfg = BL_SET_REG_BIT(tmpValRxCfg,UART_CR_URX_PRT_SEL);
            break;
        case UART_PARITY_EVEN:
            tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg,UART_CR_UTX_PRT_EN);
            tmpValTxCfg = BL_CLR_REG_BIT(tmpValTxCfg,UART_CR_UTX_PRT_SEL);
            tmpValRxCfg = BL_SET_REG_BIT(tmpValRxCfg,UART_CR_URX_PRT_EN);
            tmpValRxCfg = BL_CLR_REG_BIT(tmpValRxCfg,UART_CR_URX_PRT_SEL);
            break;
        default:
            break;
    }

    /* Configure data bits */
    tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg,UART_CR_UTX_BIT_CNT_D,(uartCfg->dataBits+4));
    tmpValRxCfg = BL_SET_REG_BITS_VAL(tmpValRxCfg,UART_CR_URX_BIT_CNT_D,(uartCfg->dataBits+4));

    /* Configure tx stop bits */
    tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg,UART_CR_UTX_BIT_CNT_P,uartCfg->stopBits);

    /* Configure tx cts flow control function */
    if(ENABLE == uartCfg->ctsFlowControl){
        tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg,UART_CR_UTX_CTS_EN);
    }else{
        tmpValTxCfg = BL_CLR_REG_BIT(tmpValTxCfg,UART_CR_UTX_CTS_EN);
    }

    /* Configure rx input de-glitch function */
    if(ENABLE == uartCfg->rxDeglitch){
        tmpValRxCfg = BL_SET_REG_BIT(tmpValRxCfg,UART_CR_URX_DEG_EN);
    }else{
        tmpValRxCfg = BL_CLR_REG_BIT(tmpValRxCfg,UART_CR_URX_DEG_EN);
    }

    /* Configure rx rts output SW control mode */
    if(ENABLE == uartCfg->rtsSoftwareControl){
        tmpValRxCfg = BL_SET_REG_BIT(tmpValRxCfg,UART_CR_URX_RTS_SW_MODE);
    }else{
        tmpValRxCfg = BL_CLR_REG_BIT(tmpValRxCfg,UART_CR_URX_RTS_SW_MODE);
    }

    /* Write back */
    BL_WR_REG(UARTx,UART_UTX_CONFIG,tmpValTxCfg);
    BL_WR_REG(UARTx,UART_URX_CONFIG,tmpValRxCfg);

    /* Configure LSB-first or MSB-first */
    tmpValTxCfg = BL_RD_REG(UARTx,UART_DATA_CONFIG);
    if(UART_MSB_FIRST == uartCfg->byteBitInverse){
        tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg,UART_CR_UART_BIT_INV);
    }else{
        tmpValTxCfg = BL_CLR_REG_BIT(tmpValTxCfg,UART_CR_UART_BIT_INV);
    }
    BL_WR_REG(UARTx,UART_DATA_CONFIG,tmpValTxCfg);

#ifndef BFLB_USE_HAL_DRIVER
    //Interrupt_Handler_Register(UART0_IRQn,UART0_IRQHandler);
    //Interrupt_Handler_Register(UART1_IRQn,UART1_IRQHandler);
#endif
    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART set default value of all registers function
 *
 * @param  uartId: UART ID type
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_DeInit(UART_ID_Type uartId)
{
    if(UART0_ID==uartId){
        GLB_AHB_Slave1_Reset(BL_AHB_SLAVE1_UART0);
    }else if(UART1_ID==uartId){
        GLB_AHB_Slave1_Reset(BL_AHB_SLAVE1_UART1);
    }

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART configure fifo function
 *
 * @param  uartId: UART ID type
 * @param  fifoCfg: FIFO configuration structure pointer
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_FifoConfig(UART_ID_Type uartId,UART_FifoCfg_Type* fifoCfg)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Deal with uart fifo configure register */
    tmpVal = BL_RD_REG(UARTx,UART_FIFO_CONFIG_1);
    /* Configure dma tx fifo threshold */
    tmpVal = BL_SET_REG_BITS_VAL(tmpVal,UART_TX_FIFO_TH,fifoCfg->txFifoDmaThreshold-1);
    /* Configure dma rx fifo threshold */
    tmpVal = BL_SET_REG_BITS_VAL(tmpVal,UART_RX_FIFO_TH,fifoCfg->rxFifoDmaThreshold-1);
    /* Write back */
    BL_WR_REG(UARTx,UART_FIFO_CONFIG_1,tmpVal);

    /* Enable or disable uart fifo dma function */
    tmpVal = BL_RD_REG(UARTx,UART_FIFO_CONFIG_0);
    if(ENABLE == fifoCfg->txFifoDmaEnable){
        tmpVal = BL_SET_REG_BIT(tmpVal,UART_DMA_TX_EN);
    }else{
        tmpVal = BL_CLR_REG_BIT(tmpVal,UART_DMA_TX_EN);
    }
    if(ENABLE == fifoCfg->rxFifoDmaEnable){
        tmpVal = BL_SET_REG_BIT(tmpVal,UART_DMA_RX_EN);
    }else{
        tmpVal = BL_CLR_REG_BIT(tmpVal,UART_DMA_RX_EN);
    }
    BL_WR_REG(UARTx,UART_FIFO_CONFIG_0,tmpVal);

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART configure infra function
 *
 * @param  uartId: UART ID type
 * @param  irCfg: IR configuration structure pointer
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_IrConfig(UART_ID_Type uartId, UART_IrCfg_Type* irCfg)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Configure tx ir mode */
    tmpVal = BL_RD_REG(UARTx,UART_UTX_CONFIG);
    if(ENABLE == irCfg->txIrEnable){
        tmpVal = BL_SET_REG_BIT(tmpVal,UART_CR_UTX_IR_EN);
    }else{
        tmpVal = BL_CLR_REG_BIT(tmpVal,UART_CR_UTX_IR_EN);
    }
    if(ENABLE == irCfg->txIrInverse){
        tmpVal = BL_SET_REG_BIT(tmpVal,UART_CR_UTX_IR_INV);
    }else{
        tmpVal = BL_CLR_REG_BIT(tmpVal,UART_CR_UTX_IR_INV);
    }
    BL_WR_REG(UARTx,UART_UTX_CONFIG,tmpVal);

    /* Configure rx ir mode */
    tmpVal = BL_RD_REG(UARTx,UART_URX_CONFIG);
    if(ENABLE == irCfg->rxIrEnable){
        tmpVal = BL_SET_REG_BIT(tmpVal,UART_CR_URX_IR_EN);
    }else{
        tmpVal = BL_CLR_REG_BIT(tmpVal,UART_CR_URX_IR_EN);
    }
    if(ENABLE == irCfg->rxIrInverse){
        tmpVal = BL_SET_REG_BIT(tmpVal,UART_CR_URX_IR_INV);
    }else{
        tmpVal = BL_CLR_REG_BIT(tmpVal,UART_CR_URX_IR_INV);
    }
    BL_WR_REG(UARTx,UART_URX_CONFIG,tmpVal);

    /* Configure tx ir pulse start and stop position */
    BL_WR_REG(UARTx,UART_UTX_IR_POSITION,irCfg->txIrPulseStop<<0x10|irCfg->txIrPulseStart);

    /* Configure rx ir pulse start position */
    BL_WR_REG(UARTx,UART_URX_IR_POSITION,irCfg->rxIrPulseStart);

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  Enable UART
 *
 * @param  uartId: UART ID type
 * @param  direct: UART direction type
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_Enable(UART_ID_Type uartId,UART_Direction_Type direct)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_DIRECTION_TYPE(direct));

    if(direct == UART_TX || direct == UART_TXRX){
        /* Enable UART tx unit */
        tmpVal = BL_RD_REG(UARTx,UART_UTX_CONFIG);
        BL_WR_REG(UARTx,UART_UTX_CONFIG,BL_SET_REG_BIT(tmpVal,UART_CR_UTX_EN));
    }

    if(direct == UART_RX || direct == UART_TXRX){
        /* Enable UART rx unit */
        tmpVal = BL_RD_REG(UARTx,UART_URX_CONFIG);
        BL_WR_REG(UARTx,UART_URX_CONFIG,BL_SET_REG_BIT(tmpVal,UART_CR_URX_EN));
    }

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  Disable UART
 *
 * @param  uartId: UART ID type
 * @param  direct: UART direction type
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_Disable(UART_ID_Type uartId,UART_Direction_Type direct)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_DIRECTION_TYPE(direct));

    if(direct == UART_TX || direct == UART_TXRX){
        /* Disable UART tx unit */
        tmpVal = BL_RD_REG(UARTx,UART_UTX_CONFIG);
        BL_WR_REG(UARTx,UART_UTX_CONFIG,BL_CLR_REG_BIT(tmpVal,UART_CR_UTX_EN));
    }

    if(direct == UART_RX || direct == UART_TXRX){
        /* Disable UART rx unit */
        tmpVal = BL_RD_REG(UARTx,UART_URX_CONFIG);
        BL_WR_REG(UARTx,UART_URX_CONFIG,BL_CLR_REG_BIT(tmpVal,UART_CR_URX_EN));
    }

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART set length of tx data transfer,tx end interrupt will assert when this length is
 *         reached
 *
 * @param  uartId: UART ID type
 * @param  length: Length of data (unit:character/byte)
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_SetTxDataLength(UART_ID_Type uartId,uint16_t length)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Set length */
    tmpVal = BL_RD_REG(UARTx,UART_UTX_CONFIG);
    BL_WR_REG(UARTx,UART_UTX_CONFIG,BL_SET_REG_BITS_VAL(tmpVal,UART_CR_UTX_LEN,length-1));

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART set length of rx data transfer,rx end interrupt will assert when this length is
 *         reached
 *
 * @param  uartId: UART ID type
 * @param  length: Length of data (unit:character/byte)
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_SetRxDataLength(UART_ID_Type uartId,uint16_t length)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Set length */
    tmpVal = BL_RD_REG(UARTx,UART_URX_CONFIG);
    BL_WR_REG(UARTx,UART_URX_CONFIG,BL_SET_REG_BITS_VAL(tmpVal,UART_CR_URX_LEN,length-1));

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART set rx time-out value for triggering RTO interrupt
 *
 * @param  uartId: UART ID type
 * @param  time: Time-out value (unit:bit time)
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_SetRxTimeoutValue(UART_ID_Type uartId,uint8_t time)
{
    uint32_t UARTx = uartAddr[uartId];
    uint32_t tmpVal;

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Set time-out value */
    tmpVal = BL_RD_REG(UARTx,UART_URX_RTO_TIMER);
    tmpVal = BL_SET_REG_BITS_VAL(tmpVal,UART_CR_URX_RTO_VALUE,time-1);
    BL_WR_REG(UARTx,UART_URX_RTO_TIMER,tmpVal);

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART set de-glitch function cycle count value
 *
 * @param  uartId: UART ID type
 * @param  deglitchCnt: De-glitch function cycle count
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_SetDeglitchCount(UART_ID_Type uartId,uint8_t deglitchCnt)
{
    uint32_t UARTx = uartAddr[uartId];
    uint32_t tmpVal;

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Set count value */
    tmpVal = BL_RD_REG(UARTx,UART_URX_CONFIG);
    tmpVal = BL_SET_REG_BITS_VAL(tmpVal,UART_CR_URX_DEG_CNT,deglitchCnt);
    BL_WR_REG(UARTx,UART_URX_CONFIG,tmpVal);

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART set tx and rx baudrate according to auto baudrate detection value
 *
 * @param  uartId: UART ID type
 * @param  autoBaudDet: Choose detection value using codeword 0x55 or start bit
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_SetBaudrate(UART_ID_Type uartId,UART_AutoBaudDetection_Type autoBaudDet)
{
    uint32_t UARTx = uartAddr[uartId];
    uint16_t tmpVal;

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Get detection value */
    tmpVal = UART_GetAutoBaudCount(uartId,autoBaudDet);

    /* Set tx baudrate */
    BL_WR_REG(UARTx,UART_BIT_PRD,tmpVal<<0x10 | tmpVal);

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART set rx rts output software control value
 *
 * @param  uartId: UART ID type
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_SetRtsValue(UART_ID_Type uartId)
{
    uint32_t UARTx = uartAddr[uartId];
    uint32_t tmpVal;

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Rts set 1*/
    tmpVal = BL_RD_REG(UARTx,UART_URX_CONFIG);
    BL_WR_REG(UARTx,UART_URX_CONFIG,BL_SET_REG_BIT(tmpVal,UART_CR_URX_RTS_SW_VAL));

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART clear rx rts output software control value
 *
 * @param  uartId: UART ID type
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_ClrRtsValue(UART_ID_Type uartId)
{
    uint32_t UARTx = uartAddr[uartId];
    uint32_t tmpVal;

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Rts clear 0 */
    tmpVal = BL_RD_REG(UARTx,UART_URX_CONFIG);
    BL_WR_REG(UARTx,UART_URX_CONFIG,BL_CLR_REG_BIT(tmpVal,UART_CR_URX_RTS_SW_VAL));

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART configure tx free run mode function
 *
 * @param  uartId: UART ID type
 * @param  txFreeRun: Enable or disable tx free run mode
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_TxFreeRun(UART_ID_Type uartId,BL_Fun_Type txFreeRun)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Enable or disable tx free run mode */
    tmpVal = BL_RD_REG(UARTx,UART_UTX_CONFIG);
    if(ENABLE == txFreeRun){
        BL_WR_REG(UARTx,UART_UTX_CONFIG,BL_SET_REG_BIT(tmpVal,UART_CR_UTX_FRM_EN));
    }else{
        BL_WR_REG(UARTx,UART_UTX_CONFIG,BL_CLR_REG_BIT(tmpVal,UART_CR_UTX_FRM_EN));
    }

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART configure auto baud rate detection function
 *
 * @param  uartId: UART ID type
 * @param  autoBaud: Enable or disable auto function
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_AutoBaudDetection(UART_ID_Type uartId,BL_Fun_Type autoBaud)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Enable or disable auto baud rate detection function */
    tmpVal = BL_RD_REG(UARTx,UART_URX_CONFIG);
    if(ENABLE == autoBaud){
        BL_WR_REG(UARTx,UART_URX_CONFIG,BL_SET_REG_BIT(tmpVal,UART_CR_URX_ABR_EN));
    }else{
        BL_WR_REG(UARTx,UART_URX_CONFIG,BL_CLR_REG_BIT(tmpVal,UART_CR_URX_ABR_EN));
    }

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART tx fifo clear
 *
 * @param  uartId: UART ID type
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_TxFifoClear(UART_ID_Type uartId)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameter */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Clear tx fifo */
    tmpVal = BL_RD_REG(UARTx,UART_FIFO_CONFIG_0);
    BL_WR_REG(UARTx,UART_FIFO_CONFIG_0,BL_SET_REG_BIT(tmpVal,UART_TX_FIFO_CLR));

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART rx fifo clear
 *
 * @param  uartId: UART ID type
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_RxFifoClear(UART_ID_Type uartId)
{
    uint32_t tmpVal = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameter */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Clear rx fifo */
    tmpVal = BL_RD_REG(UARTx,UART_FIFO_CONFIG_0);
    BL_WR_REG(UARTx,UART_FIFO_CONFIG_0,BL_SET_REG_BIT(tmpVal,UART_RX_FIFO_CLR));

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART mask or unmask certain or all interrupt
 *
 * @param  uartId: UART ID type
 * @param  intType: UART interrupt type
 * @param  intMask: UART interrupt mask value( MASK:disbale interrupt,UNMASK:enable interrupt )
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_IntMask(UART_ID_Type uartId,UART_INT_Type intType,BL_Mask_Type intMask)
{
    uint32_t tmpVal;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_INT_TYPE(intType));
    CHECK_PARAM(IS_BL_MASK_TYPE(intMask));

    tmpVal = BL_RD_REG(UARTx,UART_INT_MASK);

    /* Mask or unmask certain or all interrupt */
    if(UART_INT_ALL == intType){
        if(MASK == intMask){
            tmpVal |= 0xff;
        }else{
            tmpVal &= 0;
        }
    }else{
        if(MASK == intMask){
            tmpVal |= 1<<intType;
        }else{
            tmpVal &= ~(1<<intType);
        }
    }

    /* Write back */
    BL_WR_REG(UARTx,UART_INT_MASK,tmpVal);

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART clear certain or all interrupt
 *
 * @param  uartId: UART ID type
 * @param  intType: UART interrupt type
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_IntClear(UART_ID_Type uartId,UART_INT_Type intType)
{
    uint32_t tmpVal;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_INT_TYPE(intType));

    tmpVal = BL_RD_REG(UARTx,UART_INT_CLEAR);

    /* Clear certain or all interrupt */
    if(UART_INT_ALL == intType){
        tmpVal |= 0xff;
    }else{
        tmpVal |= 1<<intType;
    }

    /* Write back */
    BL_WR_REG(UARTx,UART_INT_CLEAR,tmpVal);

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  Install uart interrupt callback function
 *
 * @param  uartId: UART ID type
 * @param  intType: UART interrupt type
 * @param  cbFun: Pointer to interrupt callback function. The type should be void (*fn)(void)
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_Int_Callback_Install(UART_ID_Type uartId,UART_INT_Type intType,intCallback_Type* cbFun)
{
    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_INT_TYPE(intType));

    uartIntCbfArra[uartId][intType] = cbFun;

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART send data to tx fifo
 *
 * @param  uartId: UART ID type
 * @param  data: The data to be send
 * @param  len: The length of the send buffer
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_SendData(UART_ID_Type uartId, uint8_t* data,uint32_t len)
{
    uint32_t txLen = 0;
    uint32_t UARTx = uartAddr[uartId];
    uint32_t timeoutCnt = UART_TX_TIMEOUT_COUNT;

    /* Check the parameter */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Send data */
    while(txLen<len){
        if(UART_GetTxFifoCount(uartId)>0){
            BL_WR_BYTE(UARTx+UART_FIFO_WDATA_OFFSET,data[txLen++]);
            timeoutCnt = UART_TX_TIMEOUT_COUNT;
        }else{
            timeoutCnt--;
            if(timeoutCnt == 0){
                return TIMEOUT;
            }
        }
    }

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART send data to tx fifo in block mode
 *
 * @param  uartId: UART ID type
 * @param  data: The data to be send
 * @param  len: The length of the send buffer
 *
 * @return SUCCESS
 *
*******************************************************************************/
BL_Err_Type UART_SendDataBlock(UART_ID_Type uartId, uint8_t* data,uint32_t len)
{
    uint32_t txLen = 0;
    uint32_t UARTx = uartAddr[uartId];
    uint32_t timeoutCnt = UART_TX_TIMEOUT_COUNT;

    /* Check the parameter */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Send data */
    while(txLen<len){
        if(UART_GetTxFifoCount(uartId)>0){
            BL_WR_BYTE(UARTx+UART_FIFO_WDATA_OFFSET,data[txLen++]);
            timeoutCnt = UART_TX_TIMEOUT_COUNT;
        }else{
            timeoutCnt--;
            if(timeoutCnt == 0){
                return TIMEOUT;
            }
        }
    }

    while(UART_GetTxBusBusyStatus(uartId) == SET){}

    return SUCCESS;
}

/****************************************************************************//**
 * @brief  UART receive data from rx fifo
 *
 * @param  uartId: UART ID type
 * @param  data: The receive data buffer
 * @param  maxLen: The max length of the buffer
 *
 * @return The length of the received buffer
 *
*******************************************************************************/
uint32_t UART_ReceiveData(UART_ID_Type uartId,uint8_t* data,uint32_t maxLen)
{
    uint32_t rxLen = 0;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameter */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Receive data */
    while(rxLen<maxLen && UART_GetRxFifoCount(uartId)>0){
        data[rxLen++] = BL_RD_BYTE(UARTx+UART_FIFO_RDATA_OFFSET);
    }

    return rxLen;
}

/****************************************************************************//**
 * @brief  UART get auto baud count value
 *
 * @param  uartId: UART ID type
 * @param  autoBaudDet: Detection using codeword 0x55 or start bit
 *
 * @return Bit period of auto baudrate detection
 *
*******************************************************************************/
uint16_t UART_GetAutoBaudCount(UART_ID_Type uartId,UART_AutoBaudDetection_Type autoBaudDet)
{
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameter */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_AUTOBAUDDETECTION_TYPE(autoBaudDet));

    /* Select 0x55 or start bit detection value */
    if(UART_AUTOBAUD_0X55 == autoBaudDet){
        return BL_RD_REG(UARTx,UART_STS_URX_ABR_PRD)>>0x10&0xffff;
    }else{
        return BL_RD_REG(UARTx,UART_STS_URX_ABR_PRD)&0xffff;
    }
}

/****************************************************************************//**
 * @brief  UART get tx fifo unoccupied count value
 *
 * @param  uartId: UART ID type
 *
 * @return Tx fifo unoccupied count value
 *
*******************************************************************************/
uint8_t UART_GetTxFifoCount(UART_ID_Type uartId)
{
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameter */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    return BL_GET_REG_BITS_VAL(BL_RD_REG(UARTx,UART_FIFO_CONFIG_1),UART_TX_FIFO_CNT);
}

/****************************************************************************//**
 * @brief  UART get rx fifo occupied count value
 *
 * @param  uartId: UART ID type
 *
 * @return Rx fifo occupied count value
 *
*******************************************************************************/
uint8_t UART_GetRxFifoCount(UART_ID_Type uartId)
{
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameter */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    return BL_GET_REG_BITS_VAL(BL_RD_REG(UARTx,UART_FIFO_CONFIG_1),UART_RX_FIFO_CNT);
}

/****************************************************************************//**
 * @brief  Get uart interrupt status
 *
 * @param  uartId: UART ID type
 * @param  intType: UART interrupt type
 *
 * @return Status of interrupt
 *
*******************************************************************************/
BL_Sts_Type UART_GetIntStatus(UART_ID_Type uartId,UART_INT_Type intType)
{
    uint32_t tmpVal;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_INT_TYPE(intType));

    /* Get certain or all interrupt status */
    tmpVal = BL_RD_REG(UARTx,UART_INT_STS);
    if(UART_INT_ALL == intType){
        if((tmpVal&0xff) != 0)
        {
            return SET;
        }else{
            return RESET;
        }
    }else{
        if((tmpVal&(1U<<intType)) != 0)
        {
            return SET;
        }else{
            return RESET;
        }
    }
}

/****************************************************************************//**
 * @brief  Get indicator of uart tx bus busy
 *
 * @param  uartId: UART ID type
 *
 * @return Status of tx bus
 *
*******************************************************************************/
BL_Sts_Type UART_GetTxBusBusyStatus(UART_ID_Type uartId)
{
    uint32_t tmpVal;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Get tx bus busy status */
    tmpVal = BL_RD_REG(UARTx,UART_STATUS);
    if(BL_IS_REG_BIT_SET(tmpVal,UART_STS_UTX_BUS_BUSY))
    {
        return SET;
    }else{
        return RESET;
    }
}

/****************************************************************************//**
 * @brief  Get indicator of uart rx bus busy
 *
 * @param  uartId: UART ID type
 *
 * @return Status of rx bus
 *
*******************************************************************************/
BL_Sts_Type UART_GetRxBusBusyStatus(UART_ID_Type uartId)
{
    uint32_t tmpVal;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));

    /* Get rx bus busy status */
    tmpVal = BL_RD_REG(UARTx,UART_STATUS);
    if(BL_IS_REG_BIT_SET(tmpVal,UART_STS_URX_BUS_BUSY))
    {
        return SET;
    }else{
        return RESET;
    }
}

/****************************************************************************//**
 * @brief  Get tx/rx fifo overflow or underflow status
 *
 * @param  uartId: UART ID type
 * @param  overflow: Select tx/rx overflow or underflow
 *
 * @return Status of tx/rx fifo
 *
*******************************************************************************/
BL_Sts_Type UART_GetOverflowStatus(UART_ID_Type uartId,UART_Overflow_Type overflow)
{
    uint32_t tmpVal;
    uint32_t UARTx = uartAddr[uartId];

    /* Check the parameters */
    CHECK_PARAM(IS_UART_ID_TYPE(uartId));
    CHECK_PARAM(IS_UART_OVERFLOW_TYPE(overflow));

    /* Get tx/rx fifo overflow or underflow status */
    tmpVal = BL_RD_REG(UARTx,UART_FIFO_CONFIG_0);
    if((tmpVal&(1U<<(overflow+4))) !=0)
    {
        return SET;
    }else{
        return RESET;
    }
}

/****************************************************************************//**
 * @brief  Get current baudrate function
 *
 * @param  uartId: UART ID type
 *
 * @return Baudrate
 *
*******************************************************************************/
uint32_t UART_GetBaudrate(UART_ID_Type uartId)
{
    uint32_t clock = 0;
    uint32_t tmpVal = 0;
    uint32_t div1 = 1;
    uint32_t div2 = 1;
    uint32_t UARTx = uartAddr[uartId];
    
    /* Get uart clock */
    tmpVal = BL_RD_REG(GLB_BASE,GLB_CLK_CFG2);
    div2 = BL_GET_REG_BITS_VAL(tmpVal,GLB_UART_CLK_DIV)+1;
    if(BL_IS_REG_BIT_SET(tmpVal,GLB_HBN_UART_CLK_SEL)){
        clock = 160000000;
    }else{
        tmpVal = BL_RD_REG(GLB_BASE,GLB_CLK_CFG0);
        div1 = BL_GET_REG_BITS_VAL(tmpVal,GLB_REG_HCLK_DIV);
        tmpVal = BL_GET_REG_BITS_VAL(tmpVal,GLB_HBN_ROOT_CLK_SEL);
        if(tmpVal == 0){
            clock = 32000000;
        }else if(tmpVal == 1){
            clock = 40000000;
        }else{
            tmpVal = BL_RD_REG(GLB_BASE,GLB_CLK_CFG0);
            tmpVal = BL_GET_REG_BITS_VAL(tmpVal,GLB_REG_PLL_SEL);
            switch(tmpVal){
                case 0:
                    clock = 48000000;
                    break;
                case 1:
                    clock = 120000000;
                    break;
                case 2:
                    clock = 160000000;
                    break;
                case 3:
                    clock = 192000000;
                    break;
                default:
                    clock = 160000000;
                    break;
            }
        }
        clock /= div1;
    }
    clock /= div2;
    
    /* Get uart bit period */
    tmpVal = BL_RD_REG(UARTx,UART_BIT_PRD);
    tmpVal = BL_GET_REG_BITS_VAL(tmpVal,UART_CR_UTX_BIT_PRD)+1;
    
    return(clock/tmpVal);
}

/****************************************************************************//**
 * @brief  UART0 interrupt handler
 *
 * @param  None
 *
 * @return None
 *
*******************************************************************************/
#if (!defined BL602_USE_HAL_DRIVER)||(defined BL602_EFLASH_LOADER)
void UART0_IRQHandler(void)
{
    UART_IntHandler(UART0_ID);
}
#endif

/****************************************************************************//**
 * @brief  UART1 interrupt handler
 *
 * @param  None
 *
 * @return None
 *
*******************************************************************************/
#if (!defined BL602_USE_HAL_DRIVER)||(defined BL602_EFLASH_LOADER)
void UART1_IRQHandler(void)
{
    UART_IntHandler(UART1_ID);
}
#endif


/*@} end of group UART_Public_Functions */

/*@} end of group UART */

/*@} end of group BL602_Peripheral_Driver */
